home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / C and C++ / Miscellaneous / ival / ival.c < prev    next >
Encoding:
C/C++ Source or Header  |  1987-05-26  |  7.9 KB  |  318 lines  |  [TEXT/MACA]

  1. /*
  2.  * event.c - startup, stopping, and the main event loop
  3.  */
  4.  
  5. #include <quickdraw.h>
  6. #include <memory.h>
  7. #include <font.h>
  8. #include <window.h>
  9. #include <dialog.h>
  10. #include <osutil.h>
  11. #include <menu.h>
  12. #include <event.h>
  13. #include <textedit.h>
  14. #include <desk.h>
  15. #include <control.h>
  16. #include <toolutil.h>
  17.  
  18. #define DATA
  19. #include "ival.h"
  20. #undef DATA
  21.  
  22. /*
  23.  * ctbuts[] - buttons for the "Control" window pane
  24.  */
  25.  
  26. #define CTSTRS        134    /* STR# */
  27. #define CT_NEXT         0    /* "Next test"            */
  28. #define CT_PLAY         1    /* "Play the tones"        */
  29. #define CT_COUNT     2
  30. static ControlHandle ctbuts[CT_COUNT];
  31.  
  32. /*
  33.  * main() - start the program.
  34.  */
  35.  
  36. main()
  37. {
  38.     static WindowRecord wrecord;    /* Storage for window record. */
  39.     
  40.     /*
  41.      * Initialize our program.  It seems best to handle:
  42.      * Memory inits first, ToolBox inits second, then the program variables'
  43.      * inits. Note that the order of inits is important; see "Using the
  44.      * Dialog Manager" in the Dialog Mgr section.
  45.      */
  46.  
  47.     setupmemory();
  48.     InitGraf(&thePort); InitFonts(); InitWindows(); InitMenus(); TEInit();
  49.     InitDialogs((ProcPtr) 0); InitCursor();
  50.     SetEventMask(everyEvent - keyUpMask); /* set default event mask */
  51.  
  52.     /* 
  53.      * Get the port which is the whole screen, to use when deactivating
  54.      * our window.  This prevents the current grafPort pointer from
  55.      * ever dangling.
  56.      */
  57.     GetWMgrPort(&screenport);SetPort(screenport);
  58.  
  59.     /* 
  60.      * GetNewWindow posts an update event for the new window,
  61.      * so it will be redrawn right away. (-1 is the frontmost window)
  62.      * Set the default text drawing for our window.
  63.      */
  64.     windoc = GetNewWindow(WINDOWID, &wrecord, (long) -1);
  65.     SetPort(windoc); TextFont(systemFont);
  66.     
  67.     /*
  68.      * set who initially provides what.
  69.      */
  70.  
  71.     progtasks.notate = TRUE;
  72.     studtasks.notate = FALSE;
  73.     progtasks.name = FALSE;
  74.     studtasks.name = TRUE;
  75.     progtasks.sound = TRUE;
  76.     studtasks.sound = FALSE;
  77.  
  78.     /*
  79.      * Set how notes are played
  80.      * and whether accidentals are allowed.
  81.      */
  82.  
  83.     any_seq = SEQ_MEL;
  84.     acc_ok = FALSE;
  85.  
  86.     setupmenus();    /* pull in and setup our menus            */
  87.     fillwindow();    /* auto-shape the window            */
  88.     mus4init();        /* init the four-part music player        */
  89.     nexttest();
  90.     while (doevent())    /* do the event-driven part of the program    */
  91.     ;
  92.     closeup();
  93. }
  94.  
  95. /*
  96.  * closeup() - prepare to exit the program. (called before exiting).
  97.  * Restore the state of the machine so the finder will be happy.
  98.  */
  99. closeup()
  100. {
  101.     InitCursor();
  102.     SetEventMask(everyEvent - keyUpMask);
  103. }
  104.  
  105. /*
  106.  * fillcntl() - fill in the 'control' pane.
  107.  */
  108.  
  109. fillcntl()
  110. {
  111.     short numstrs;    /* number of strings in the current STR# resource*/
  112.     Point delta;    /* a temporary distance                */
  113.     short width;    /* a width (in pixels)                */
  114.     Rect tmprect;    /* a temporary variable                */
  115.  
  116.     /*
  117.      * put all the control buttons in a horizontal line just below the
  118.      * top of the control rectangle.
  119.      */
  120.  
  121.     width = strswidth(CTSTRS, &numstrs) + BUTEXTRAH;
  122.     tmprect.left = (cntlrect.left + cntlrect.right) / 2 -
  123.       ((width + BUTHMARG) * numstrs) / 2;
  124.     tmprect.right = tmprect.left + width;
  125.     tmprect.top = cntlrect.top + HMARGIN;
  126.     tmprect.bottom = tmprect.top + BUTHEIGHT;
  127.     delta.h = width + BUTHMARG;
  128.     delta.v = 0;
  129.     makeradcol(ctbuts, BUTPROCID, CTSTRS, &tmprect, delta.h, delta.v);
  130. }
  131.  
  132. /*
  133.  * cntlpress() - handle a button press within the Control pane.
  134.  */
  135.  
  136. cntlpress(whichcontrol)
  137. ControlHandle whichcontrol;
  138. {
  139.     short semi1;
  140.     short semi2;
  141.     struct atone midc;
  142.     short butidx;        /* index of the pressed button    */
  143.     
  144.     /*
  145.      * If the button was 'Next', start the next test.
  146.      * if the button was 'Play',
  147.      *   play the desired harmonic or melodic interval.
  148.      */
  149.  
  150.     for (butidx = 0; butidx < CT_COUNT; ++butidx) {
  151.         if (whichcontrol == ctbuts[butidx]) break;
  152.     }
  153.     switch (butidx) {
  154.     case CT_NEXT:
  155.     nexttest();
  156.     break;
  157.     case CT_PLAY:
  158.     midc.degree = DEG_MIDC;
  159.     midc.chrome = CH_NAT;
  160.     semi1 = tonetosemi(&curtone[0]) - tonetosemi(&midc);
  161.     semi2 = tonetosemi(&curtone[1]) - tonetosemi(&midc);
  162.     switch (cur_seq) {
  163.     case SEQ_HARM:
  164.         mus4play(60, semi1, semi2, 1000, 1000);
  165.         break;
  166.     case SEQ_MEL:
  167.         mus4play(30, semi1, 1000, 1000, 1000);
  168.         mus4play(30, semi2, 1000, 1000, 1000);
  169.         break;
  170.     }
  171.     break;
  172.     }
  173. }
  174.  
  175. /*
  176.  * nexttest() - choose a new exercise.
  177.  */
  178.  
  179. nexttest()
  180. {
  181.     short mindeg, maxdeg;    /* limits of degrees to choose        */
  182.     short degs;            /* # of degrees in the interval        */
  183.     short semis;        /* base # of semitones in the interval    */
  184.     short hasname[NUM_CH][NUM_CH]; /* tone1.chrome to tone2.chrome named?*/
  185.     short ch1, ch2;        /* .chrome for each tone        */
  186.     short nummods;        /* number of legal chromatic mods    */
  187.     short modidx;        /* index of the chosen modifier        */
  188.     struct ivinfo *ivp;
  189.     short i;
  190.     short tonetosemi();
  191.  
  192.     pickkey();
  193.     InvalRect(&scorerect);
  194.  
  195.     /*
  196.      * Pick a degree for each of the tones;
  197.      * The second must fall within an octave of the first
  198.      * (and within the limits of the score range).
  199.      */
  200.  
  201.     curtone[0].degree = randint(DEGPERSCORE);
  202.     curtone[0].chrome = CH_NAT;
  203.     
  204.     mindeg = curtone[0].degree - DEGPEROCT;
  205.     if (mindeg < 0) mindeg = 0;
  206.     maxdeg = curtone[0].degree + DEGPEROCT;
  207.     if (maxdeg > DEGPERSCORE - 1) maxdeg = DEGPERSCORE - 1;
  208.     curtone[1].degree = mindeg + randint(maxdeg - mindeg + 1);
  209.     curtone[1].chrome = CH_NAT;
  210.  
  211.     degs = curtone[1].degree - curtone[0].degree;
  212.     if (degs < 0) degs = -degs;
  213.     
  214.     /*
  215.      * If it's not ok to have accidentals,
  216.      *   use the chromatic modifications of the key signature.
  217.      * Otherwise, pick random, but possible, chromatic changes to the two tones:
  218.      *   First find what (and how many) changes are possible;
  219.      *   Then pick one of them.
  220.      */
  221.     
  222.     if (!acc_ok) {
  223.     for (i = 0; i < NUMTONES; ++i) {
  224.         curtone[i].chrome = chromeofdeg(curtone[i].degree);
  225.     }
  226.     } else {
  227.     nummods = 0;
  228.     for (ch1 = CH_FLAT; ch1 <= CH_SHARP; ++ch1) {
  229.         for (ch2 = CH_FLAT; ch2 <= CH_SHARP; ++ch2) {
  230.         hasname[ch1 - CH_FLAT][ch2 - CH_FLAT] = FALSE;
  231.         semis = tonetosemi(&curtone[1]) + ch2 -
  232.           (tonetosemi(&curtone[0]) + ch1);
  233.         if ((curtone[0].degree < curtone[1].degree && semis < 0) ||
  234.           (curtone[0].degree > curtone[1].degree && semis > 0)) {
  235.             continue;    /* adjustments cross */
  236.         }
  237.         if (semis < 0) semis = -semis;
  238.         for (ivp = &ivinfo[0]; ivp->semis >= 0; ++ivp) {
  239.             if (ivp->semis == semis && ivp->degs == degs) {
  240.             hasname[ch1 - CH_FLAT][ch2 - CH_FLAT] = TRUE;
  241.             ++nummods;
  242.             break;
  243.             }
  244.         }
  245.         }
  246.     }
  247.     if (nummods > 0) {
  248.         modidx = randint(nummods);
  249.         for (ch1 = CH_FLAT; ch1 <= CH_SHARP && modidx >= 0; ++ch1) {
  250.         for (ch2 = CH_FLAT; ch2 <= CH_SHARP && modidx >= 0; ++ch2) {
  251.             if (hasname[ch1 - CH_FLAT][ch2 - CH_FLAT]) {
  252.             if (--modidx < 0) {
  253.                 curtone[0].chrome = ch1;
  254.                 curtone[1].chrome = ch2;
  255.             }
  256.             }
  257.         }
  258.         }
  259.     }
  260.     }
  261.     
  262.     /*
  263.      * get the size and type of the new interval.
  264.      */
  265.  
  266.     semis = tonetosemi(&curtone[1]) - tonetosemi(&curtone[0]);
  267.     if (semis < 0) semis = -semis;
  268.     
  269.     for (ivp = &ivinfo[0]; ivp->semis >= 0; ++ivp) {
  270.     if (ivp->semis == semis && ivp->degs == degs) {
  271.         curisize = degs;
  272.         curitype = ivp->qual;
  273.         break;
  274.     }
  275.     }
  276.  
  277.     /*
  278.      * choose how to play the tones:
  279.      * If the type is restricted, do just the restricted type;
  280.      * Otherwise, choose a type at random.
  281.      */
  282.  
  283.     if (any_seq != SEQ_MIX) {
  284.     cur_seq = any_seq;
  285.     } else {
  286.     cur_seq = randint(NUM_SEQ);
  287.     }
  288.     
  289.     newname();
  290.     newtones();
  291. }
  292.  
  293. /*
  294.  * tonetosemi() - give the semitone number (relative to Low C) of the
  295.  *  given tone.
  296.  */
  297.  
  298. short
  299. tonetosemi(tp)
  300. struct atone *tp;    /* the tone to convert    */
  301. {
  302.     short semi;        /* the result to return    */
  303.     static short semodeg[DEGPEROCT] = {
  304.      0,    /* C */
  305.      2,    /* D */
  306.      4,    /* E */
  307.      5,    /* F */
  308.      7,    /* G */
  309.      9,    /* A */
  310.     11    /* B */
  311.     };
  312.     
  313.     semi = (tp->degree / DEGPEROCT) * SEMPEROCT;
  314.     semi += semodeg[tp->degree % DEGPEROCT];
  315.     semi += tp->chrome;
  316.     return(semi);
  317. }
  318.